package xrpc

import (
	ctls "crypto/tls"
	"crypto/x509"
	"gitee.com/xiedongji/antgo/cpts/xlog"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"
	"net"
	"os"
)

func GetRpcServer(tls *Tls, opt ...grpc.ServerOption) *Server {
	s := &Server{
		opt: opt,
		tls: tls,
	}
	return s
}

type Server struct {
	grpcServer *grpc.Server
	opt        []grpc.ServerOption
	middleware []grpc.UnaryServerInterceptor
	tls        *Tls
}

type Tls struct {
	Crt   string
	Key   string
	CACrt string
}

// 添加中间件
func (t *Server) Use(middleware ...grpc.UnaryServerInterceptor) {
	t.middleware = append(t.middleware, middleware...)
}

func (t *Server) NewServer() (server *grpc.Server, err error) {
	if t.grpcServer == nil {
		// 添加 多个中间件
		t.opt = append(t.opt, grpc.UnaryInterceptor(ChainUnaryServer(t.middleware...)))
		// tls 配置
		if t.tls != nil {
			certificate, err := ctls.LoadX509KeyPair(t.tls.Crt, t.tls.Key)
			if err != nil {
				return nil, err
			}

			certPool := x509.NewCertPool()
			ca, err := os.ReadFile(t.tls.CACrt)
			if err != nil {
				return nil, err
			}

			if ok := certPool.AppendCertsFromPEM(ca); !ok {
				panic("AppendCertsFromPEM failed")
			}

			creds := credentials.NewTLS(&ctls.Config{
				Certificates: []ctls.Certificate{certificate},
				ClientAuth:   ctls.RequireAndVerifyClientCert,
				ClientCAs:    certPool,
			})

			t.opt = append(t.opt, grpc.Creds(creds))
		}

		t.grpcServer = grpc.NewServer(t.opt...)
	}

	return t.grpcServer, nil
}

// 启动 GRPC　监听服务
func (t *Server) Run(addr string) error {
	listener, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}

	xlog.Logger("grpc", "run").Info().Str("addr", addr).Msg("server ready")
	if err := t.grpcServer.Serve(listener); err != nil {
		xlog.Logger("grpc", "run").Error().Err(err).Send()
		return err
	}

	return nil
}
